class Counter:
    def __init__(self, line_points):
        self.line_points = line_points
        self.in_counts = 0
        self.out_counts = 0
        self.history = {}
        self.counted_ids = set()

    def _get_center(self, bbox):
        x1, y1, x2, y2 = bbox
        return int((x1 + x2) / 2), int((y1 + y2) / 2)

    def update(self, tracks):
        in_ids = []
        out_ids = []
        for track in tracks:
            x1, y1, x2, y2, track_id = track.astype(int)
            center = self._get_center((x1, y1, x2, y2))

            if track_id not in self.history:
                self.history[track_id] = []
            self.history[track_id].append(center)

            if len(self.history[track_id]) < 2:
                continue

            if track_id in self.counted_ids:
                continue

            prev_point = self.history[track_id][-2]
            curr_point = self.history[track_id][-1]

            if self._intersect(prev_point, curr_point, self.line_points[0], self.line_points[1]):
                direction = self._get_direction(prev_point, curr_point, self.line_points)
                if direction < 0:
                    self.in_counts += 1
                    in_ids.append(track_id)
                    self.counted_ids.add(track_id)
                elif direction > 0:
                    self.out_counts += 1
                    out_ids.append(track_id)
                    self.counted_ids.add(track_id)
        return in_ids, out_ids

    def _intersect(self, p1, p2, p3, p4):
        # Check if line segments (p1, p2) and (p3, p4) intersect.
        def on_segment(p, q, r):
            if (q[0] <= max(p[0], r[0]) and q[0] >= min(p[0], r[0]) and
                    q[1] <= max(p[1], r[1]) and q[1] >= min(p[1], r[1])):
                return True
            return False

        def orientation(p, q, r):
            val = (q[1] - p[1]) * (r[0] - q[0]) - (q[0] - p[0]) * (r[1] - q[1])
            if val == 0: return 0  # Collinear
            return 1 if val > 0 else 2  # Clockwise or Counterclockwise

        o1 = orientation(p1, p2, p3)
        o2 = orientation(p1, p2, p4)
        o3 = orientation(p3, p4, p1)
        o4 = orientation(p3, p4, p2)

        if o1 != o2 and o3 != o4:
            return True

        return False

    def _get_direction(self, p1, p2, line):
        # Use cross-product to determine direction of crossing.
        line_p1, line_p2 = line
        v_line = (line_p2[0] - line_p1[0], line_p2[1] - line_p1[1])
        v_track = (p2[0] - p1[0], p2[1] - p1[1])
        return v_line[0] * v_track[1] - v_line[1] * v_track[0]